package view

import (
	"crypto/md5"
	"encoding/base64"
	"encoding/binary"
	"errors"
	"fmt"
	gowin32wx "github.com/gorpher/gowin32"
	golnk "github.com/parsiya/golnk"
	uuid "github.com/satori/go.uuid"
	"github.com/sirupsen/logrus"
	"github.com/wailsapp/wails/v2/pkg/runtime"
	"image"
	"image/png"
	"io"
	"os"
	"path/filepath"
	"strings"
)

func (a *App) OpenFileDialog() (string, error) {
	logrus.Debugf("OpenFileDialog")
	options := runtime.OpenDialogOptions{
		Title:            "选择文件", // 对话框标题
		DefaultDirectory: "",     // 默认路径（空表示当前目录）
	}
	filePath, err := runtime.OpenFileDialog(a.ctx, options)
	if err != nil {
		return "", fmt.Errorf("对话框打开失败: %v", err)
	}
	if filePath == "" {
		return "", fmt.Errorf("用户取消了选择")
	}
	return filePath, nil
}

func (a *App) GetMd5(fp string) (str string, err error) {
	logrus.Debugf("DevTool.GetMd5(%s)", fp)
	file, err := os.Open(fp)
	if err != nil {
		return
	}
	defer file.Close()
	hash := md5.New()
	if _, err = io.Copy(hash, file); err != nil {
		return
	}
	bs := hash.Sum(nil)
	str = fmt.Sprintf("%x", bs)
	logrus.Debugf("DevTool.str: %s", str)
	return
}

func (a *App) GetBase64(fp string) (str string, err error) {
	file, err := os.Open(fp)
	if err != nil {
		return "", err
	}
	defer file.Close()
	data, err := io.ReadAll(file)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(data), nil
}

type AppInfo struct {
	AppName   string `json:"appName"`
	LinkPath  string `json:"linkPath"` //应用路径，如果是快捷方式，快捷方式的路径
	ExePath   string `json:"exePath"`  // 应用实际执行文件的路径
	AppParams string `json:"appParams"`
	WorkSpace string `json:"workSpace"`
	IconPath  string `json:"iconPath"`
}

func (a *App) LnkInfo(fp string) (m AppInfo, err error) {
	lf, err := golnk.File(fp)
	if err != nil {
		return
	}
	lname := filepath.Base(fp)
	appName := strings.TrimSuffix(lname, filepath.Ext(lname))
	m = AppInfo{
		AppName:   appName,
		LinkPath:  fp,
		ExePath:   lf.LinkInfo.LocalBasePath,
		AppParams: lf.StringData.CommandLineArguments,
		WorkSpace: lf.StringData.WorkingDir,
		IconPath:  lf.StringData.IconLocation,
	}
	return m, nil
}
func (a *App) Lnk2Png(fp string) (imgStr string, err error) {
	var flnk golnk.LnkFile
	flnk, err = golnk.File(fp)
	if err != nil {
		err = errors.New(fmt.Sprintf("无效的lnk path:%s", fp))
		return
	}
	if strings.HasSuffix(flnk.StringData.IconLocation, ".ico") {
		imgStr = icoToBase64(flnk.StringData.IconLocation)
	} else {
		imgStr, err = a.Exe2Png(flnk.LinkInfo.LocalBasePath)
		if err != nil {
			logrus.Errorf("Exe2Png err:%v", err)
		}
	}
	return
}
func (a *App) Exe2Png(fp string) (str string, err error) {
	return ExtractPrivateExtractIcons(fp)
}

// icoToBase64 将ico中的第一个图像转换为png格式
func icoToBase64(iconPath string) (str string) {
	var (
		f   *os.File
		err error
	)
	f, err = os.Open(iconPath)
	if err != nil {
		return
	}
	defer f.Close()
	// 读取ICO文件头
	var header struct {
		Reserved uint16
		Type     uint16
		Count    uint16
	}
	if err = binary.Read(f, binary.LittleEndian, &header); err != nil {
		return
	}

	// 读取图标目录
	dirEntries := make([]struct {
		Width    uint8
		Height   uint8
		Colors   uint8
		Reserved uint8
		Planes   uint16
		BitCount uint16
		Size     uint32
		Offset   uint32
	}, header.Count)
	if err = binary.Read(f, binary.LittleEndian, &dirEntries); err != nil {
		return
	}
	if len(dirEntries) < 1 {
		return
	}

	// 读取第一个图标数据
	_, _ = f.Seek(int64(dirEntries[0].Offset), 0)
	icoData := make([]byte, dirEntries[0].Size)
	if _, err = f.Read(icoData); err != nil {
		err = errors.New(fmt.Sprintf("无法读取ICO图标数据:%s", err))
		return
	}
	// 这个png图片有可能是可以打开但是转换为base64后浏览器无法识别的情况
	// 可能是看图软件做了兼容，具体情况后面在研究
	execPath, err := os.Executable()
	if err != nil {
		return
	}
	pngImg := filepath.Join(filepath.Dir(execPath), uuid.NewV4().String()+".png")
	pngFile, err := os.Create(pngImg)
	if err != nil {
		err = errors.New(fmt.Sprintf("无法创建PNG文件:%s", err))
		return
	}
	defer pngFile.Close()
	if _, err = pngFile.Write(icoData); err != nil {
		err = errors.New(fmt.Sprintf("无法写入PNG文件:%s", err))
		return
	}
	str = base64.StdEncoding.EncodeToString(icoData)
	return
}

func ExtractPrivateExtractIcons(execPath string) (str string, err error) {
	var img image.Image
	img, err = gowin32wx.ExtractPrivateExtractIcons(execPath, 128, 128)
	if err != nil {
		return
	}

	file, err := os.Create("output.png")
	if err != nil {
		return
	}
	defer file.Close()
	err = png.Encode(file, img)
	if err != nil {
		return
	}

	b, err := io.ReadAll(file)
	if err != nil {
		return
	}
	str = base64.StdEncoding.EncodeToString(b)
	return
}
